' maxedit image editor

Strict

Import brl.pngloader
Import brl.bmploader
Import brl.tgaloader
Import brl.jpgloader

Import "../maxtk/maxtk.bmx"
'Import axe.MaxEdit
Import brl.Max2D

Const SAVEIMAGEFILTER$="Portable Network Graphics (*.png):png;Joint Photographic Experts Group (*.jpg):jpg;"

Type TNewImageRequester Extends TRequester
	Field	owner:TImagePlugin
	Field	path$
	Field	width:TGadget
	Field	height:TGadget

	Method Show()
		Super.Show()
		ActivateGadget width
	End Method

	Method DoShow(file$)
		path=file$
		Show
	End Method

	Method OnEvent()
		Local	id,data,index
		id=EventID()
		data=EventData()
		Select EventSource()
			Case window
				If EventID()=EVENT_WINDOWCLOSE
					Hide
				EndIf
			Case ok
				Local w=Int(TextFieldText(width))
				Local h=Int(TextFieldText(height))
				If w And h 
					TImageView.Open(owner,path,CreateImage(w,h))
				EndIf
				Hide			
			Case cancel
				Hide
		End Select
	End Method

	Function Create:TNewImageRequester(plugin:TImagePlugin)
		Local	req:TNewImageRequester
		req=New TNewImageRequester	
		req.owner=plugin	
		req.initrequester(plugin.host,"Create New Image",400,256)
		CreateLabel("Width",6,18,80,24,req.window)
		req.width=CreateTextField(88,14,40,20,req.window)
		CreateLabel("Height",6,48,80,24,req.window)
		req.height=CreateTextField(88,44,40,20,req.window)		
		Return req
	End Function

End Type

Type TImageOptions Extends TOptionsPage
	Field	owner:TImagePlugin
	Field	imageeditorpath:TPathButton
	
	Method CreateImageOptions:TImageOptions(plugin:TImagePlugin)
		SetName "Image Options"
		owner=plugin
		plugin.editor.hostoptions.AddPage Self
		Local defpath$
?win32
		defpath="mspaint.exe"
?	
		imageeditorpath=AddPathButton("Image Editor Path",defpath)
		layout
		Return Self
	End Method
End Type

Type TImagePlugin Extends TPlugin
	Field	editor:TEditor
	Field	newimagereq:TNewImageRequester
	Field	options:TImageOptions
'	Field	editmenu:TGadget

	Method Open:Object(path$)
		Return TImageView.Open(Self,path)
	End Method
	
	Method Initialize(owner:THost)
		host=owner
		SetName("Image",["png","jpg","bmp","tga"])
		editor=TEditor(host)
		If Not editor RuntimeError "ImagePlugin requires TEditor Host"
		newimagereq=TNewImageRequester.Create(Self)
		options=New TImageOptions.CreateImageOptions(Self)
'		editmenu=CreateEditMenu()
	End Method

	Method ShowNewRequester(path$)
		newimagereq.DoShow(path$)
	End Method
End Type

Type TImageNode Extends TDataNode
	Field	owner:TImageView
	Field	image:TImage
	
	Method Invoke(command$,argument:Object=Null)
		Select command
			Case "ACTIVATE"
'				owner.ShowPos(pos)
		End Select
	End Method

	Method Sync(snap:TDataNode)
		Local	n:TImageNode		
		If snap.name<>name SetName(snap.name)
		n=TImageNode(snap)
		If n image=n.image	'clone!
		Super.Sync(snap)
	End Method
	
	Method SetName(n$)
		Local	p
		p=n.find("'")
		If p<>-1 n=n[..p]
		name=n.Trim()
	End Method
			
	Method CreateImageNode:TImageNode(_owner:TImageView,_image:TImage)
		owner=_owner
		image=_image
		SetName "IMAGE"
		Return Self		
	End Method
	
End Type

'		vsplit=TSplitter.Create(TSplitter.VERTICAL,vsplitpos,options.navswap,tabbar,navbar.tabber)

Function DrawBox(x#,y#,w#,h#)
	DrawRect x,y,w,1
	DrawRect x,y+h-1,w,1
	DrawRect x,y+1,1,h-2
	DrawRect x+w-1,y+1,1,h-2
End Function

Function DrawFrame(x#,y#,w#,h#)
	SetAlpha 0.5
	SetColor 0,0,0
	drawbox x-1,y-1,w+1,h+1
	SetColor 255,255,255
	drawbox x-2,y-2,w+3,h+3
	SetAlpha 1
End Function

Type TImageView Extends TToolPanel
	Field	host:THost
	Field	plugin:TImagePlugin
	
	Field	vsplit:TSplitter
	Field	hsplit:TSplitter
	Field	canvas:TGadget
	Field	tools:TGadget

	Field	zlabel:TGadget
	Field	zslider:TGadget
	Field	pan:TGadget
	Field	pancan:TGadget
	
	Field	edit:TGadget
	
	Field	image:TImage
'	Field	pixmap:TPixmap
	Field	zoom#=1.0
	Field	zoomx,zoomy
	Field	panzoom#
	Field	viewx,viewy,vieww,viewh
	
	Field	dirty=True	
	
	Method Refresh()
		zoom=SliderValue(zslider)
		zoom=1.0*(2.0^zoom)
		SetGadgetText zlabel,"zoom="+zoom
		RedrawGadget pan
		RedrawGadget canvas		
		vieww=canvas.width/zoom
		viewh=canvas.height/zoom
	End Method
	
	Method DrawPan()
		SetGraphics CanvasGraphics(pan)		
		SetBlend ALPHABLEND
		Cls
		If image
			Local w#=Float(pan.width)/image.width
			Local h#=Float(pan.height)/image.height
			If h<w w=h
			panzoom=w
			SetScale panzoom,panzoom
			DrawImage image,0,0
			SetScale 1,1
			DrawFrame viewx,viewy,vieww,viewh		
		EndIf
		Flip
	End Method

	Method DrawCanvas()
		SetGraphics CanvasGraphics(canvas)		
		SetViewport 0,0,GadgetWidth(canvas),GadgetHeight(canvas) 
		SetBlend ALPHABLEND
		Cls
		SetScale zoom,zoom
		If image
			DrawImage image,0,0
		EndIf
		Flip
	End Method

	Method EditCanvas()
		If Save()
			Local file$=path
?win32
			file$=file.Replace("/","\")
?
			Local editapp$
			editapp=plugin.options.imageeditorpath.path
			If editapp system_ editapp+" ~q"+file+"~q"
		EndIf
	End Method

	Method OnEvent()
		Select EventSource()
			Case edit
				EditCanvas
			Case canvas
				Select EventID()
					Case EVENT_GADGETPAINT
						DrawCanvas
				End Select
			Case pan
				Select EventID()
					Case EVENT_GADGETPAINT
						DrawPan
					Case EVENT_MOUSEMOVE
						If EventData()=1 Print "mx="+EventX()+" my="+EventY()
				End Select				
			Case zslider
				Refresh
		End Select
	End Method

	Method Create:TImageView(_plugin:TImagePlugin,_image:TImage,file$)
		Local	stream:TStream
		plugin=_plugin
		image=_image
		host=plugin.host
		path=host.FullPath(file)		
		name=StripDir(path)
		host.AddPanel Self
		tools=CreatePanel(0,0,120,ClientHeight(panel),panel,0)				
		canvas=CreateCanvas(120,0,ClientWidth(panel)-80,ClientHeight(panel),panel,0)
		SetGadgetLayout canvas,1,1,1,1
		vsplit=TSplitter.Create(TSplitter.VERTICAL,120,3,canvas,tools,panel)
		Local y,w
		y=4
		w=ClientWidth(tools)
		zslider=CreateSlider(0,y,w,20,tools,SLIDER_HORIZONTAL|SLIDER_TRACKBAR)
		SetSliderRange zslider,-5,5
		SetSliderValue zslider,0
		y:+20
		zlabel=CreateLabel("Zoom",0,y,w,20,tools,LABEL_CENTER)
		y:+20
		pan=CreateCanvas(0,y,w,w,tools)
		y:+w+4
		edit=CreateButton("Edit",0,y,w,24,tools)
		ActivateGadget canvas
		Refresh
'		host.AddRecent path
		Return Self
	End Method
	
	Field	imagenode:TDataNode

	Method GetNode:TDataNode()		
		Local	root:TDataNode
		Local	brushes:TDataNode
		Local	textures:TDataNode
		
		root=New TDataNode.Create(StripDir(path))		

		If imagenode
			imagenode.Sync(root)	
			root.Free
		Else
			imagenode=root
		EndIf
		Return imagenode
	End Method
	
	Method SaveImage(file$)
		Local pixmap:TPixmap		
		pixmap=LockImage(image)
		Select ExtractExt(file).ToLower()
		Case "png"
			SavePixmapPNG pixmap,file	'todo: get quality...
		Case "jpg"
			SavePixmapJPeg pixmap,file	'todo: get quality...
		Default	'Case "bmp"
			Notify "Only images saved in jpg and png file formats currently supported"
			UnlockImage image
			Return True
		End Select
		UnlockImage image
'		path=file
		path=host.FullPath(file)
	End Method
	
	Method Save()
		Local	file$
		file=path
		If path.find("/tmp/")<>-1
			file=RequestFile("Save As","Portable Network Graphics (*.png):png;",True,"")
			If file="" Return False
			If ExtractExt(file)="" file=file+".png"
			dirty=True
		EndIf
		If dirty SaveImage(file)
		Return True
	End Method

	Method Invoke(command$,argument:Object=Null)
		Local	file$,ex$
		Local	p,res
		Select command
			Case "SHOW"
				If canvas ActivateGadget canvas
				host.SetTitle path				
				host.SetCodeNode GetNode()
			Case "CLOSE"
				host.RemovePanel Self
			Case "ACTIVATE"
				If canvas ActivateGadget canvas
			Case "SAVE"
				Save
			Case "QUICKSAVE"
				file=path
				If dirty SaveImage(file)
			Case "SAVEAS"
				file=path
				If host.IsTempPath(path) file$=""
				file=RequestFile("Save As",SAVEIMAGEFILTER,True,file)
				If file="" Return
				ex$=ExtractExt(file)
				If ex$="" file=file+".png"
				SaveImage(file$)
				If imagenode imagenode.detach;imagenode=Null
				host.RemovePanel Self
				host.OpenSource file	'was path				
			Case "GOTO"
			Case "FIND"
			Case "FINDNEXT"
			Case "REPLACE"
			Case "BUILD"
			Case "RUN"
			Case "LOCK"
			Case "UNLOCK"
			Case "HELP"
			Case "UNDO"
			Case "REDO"
			Case "REFRESH"
			Case "CUT"
			Case "COPY"
			Case "PASTE"
			Case "SELECTALL" 
		End Select
	End Method

	Function Open:TImageView(plugin:TImagePlugin,path$,image:TImage=Null)
		If path And Not image image=LoadImage( path )		
		If Not image plugin.ShowNewRequester(path);Return
		Return New TImageView.Create(plugin,image,path)		
	End Function

End Type
